import * as THREE from 'three'

let currentBaseAction = 'idle'
const mixerObj:{
    [key:string]: THREE.AnimationMixer
} = {

}
const Fade = {
    setMixer(_mixer:THREE.AnimationMixer, uuid:string) {
        mixerObj[uuid] = _mixer
    },
    activateAction,
    prepareCrossFade
    // prepareCrossFade( currentAction, action, 0.35 )
}

function activateAction( action:THREE.AnimationAction, weight:number ) {
    setWeight( action, weight);
    action.play();

}
async function prepareCrossFade( startAction:THREE.AnimationAction, endAction:THREE.AnimationAction, duration = 1, uuid:string ) {

    // If the current action is 'idle', execute the crossfade immediately;
    // else wait until the current action has finished its current loop

    if ( currentBaseAction === 'idle' || ! startAction || ! endAction ) {

        await executeCrossFade( startAction, endAction, duration );

    } else {

        await synchronizeCrossFade( startAction, endAction, duration, uuid );

    }

    // Update control colors

    if ( endAction ) {

        const clip = endAction.getClip();
        currentBaseAction = clip.name;

    } else {

        currentBaseAction = 'None';

    }

}
function synchronizeCrossFade( startAction:THREE.AnimationAction, endAction:THREE.AnimationAction, duration=0.35, uuid:string ) {
    return new Promise(res => {
        mixerObj[uuid].addEventListener( 'loop', onLoopFinished );

        function onLoopFinished( event:any ) {
            
            if ( event.action === startAction ) {
                mixerObj[uuid].removeEventListener( 'loop', onLoopFinished );

                executeCrossFade( startAction, endAction, duration ).then(() => {
                    res(true)
                });
                
            }

        }
    })

}

function executeCrossFade( startAction:THREE.AnimationAction, endAction:THREE.AnimationAction, duration=0.35 ) {

    if ( endAction ) {

        setWeight( endAction, 1 );
        endAction.time = 0;

        if ( startAction ) {
            startAction.crossFadeTo( endAction, duration, true );

        } else {
            endAction.fadeIn( duration );
        }

    } else {
        startAction.fadeOut( duration );

    }
    return new Promise(res => {
        setTimeout(() => {
            res(true)
        }, duration * 1000)
    })

}
function setWeight( action:THREE.AnimationAction, weight:number ) {

    action.enabled = true;
    action.setEffectiveTimeScale( 1 );
    action.setEffectiveWeight( weight );

}
export {Fade}